package vip.xls8z.learning.nio.channel;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.sql.Time;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Slf4j
public class NioEchoClient {

    public static void main(String[] args) throws IOException, InterruptedException {
        Selector selector = Selector.open();
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        socketChannel.connect(new InetSocketAddress("127.0.0.1", 8091));
        socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ);

        boolean flag = true;
        while (flag) {
            selector.select();
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> selectionKeyIter = selectionKeys.iterator();
            while (selectionKeyIter.hasNext()) {
                SelectionKey selectionKey = selectionKeyIter.next();
                if (selectionKey.isConnectable()) {
                    SocketChannel client = (SocketChannel) selectionKey.channel();
                    if (client == null) continue;
                    client.finishConnect();
                    log.info("Connectable");
                    client.register(selector, SelectionKey.OP_WRITE);
                    selectionKey.selector().wakeup();
                }

                if (selectionKey.isReadable()) {
                    SocketChannel client = (SocketChannel) selectionKey.channel();
                    if (client == null) continue;

                    ByteBuffer inputBuff = ByteBuffer.allocate(128);
                    int length = client.read(inputBuff);
                    if (length == -1) {
                        client.close();
                        selectionKey.cancel();
                        flag = false;
                        continue;
                    }

                    log.info("Readable [From Server]: {}", new String(inputBuff.array(), 0, length));
                    TimeUnit.SECONDS.sleep(2);
                    client.register(selector, SelectionKey.OP_WRITE);
                    selectionKey.selector().wakeup();
                }

                if (selectionKey.isWritable()) {
                    SocketChannel client = (SocketChannel) selectionKey.channel();
                    if (client == null) continue;

                    ByteBuffer outputBuff = ByteBuffer.allocate(128);
                    outputBuff.clear();
                    outputBuff.put(("Hello, Server. " + UUID.randomUUID()).getBytes(StandardCharsets.UTF_8));
                    outputBuff.flip();
                    client.write(outputBuff);

                    client.register(selector, SelectionKey.OP_READ);
                    selectionKey.selector().wakeup();
                }
            }
            selectionKeys.clear();
        }
        socketChannel.close();
    }
}
